package cn.com.cetccst.mdm.engine;

import static com.miui.enterprise.sdk.ApplicationManager.FLAG_ALLOW_AUTOSTART;
import static com.miui.enterprise.sdk.ApplicationManager.FLAG_GRANT_ALL_RUNTIME_PERMISSION;
import static com.miui.enterprise.sdk.ApplicationManager.FLAG_KEEP_ALIVE;
import static com.miui.enterprise.sdk.ApplicationManager.FLAG_PREVENT_UNINSTALLATION;
import static com.miui.enterprise.sdk.PhoneManager.FLAG_DISALLOW_IN;
import static com.miui.enterprise.sdk.PhoneManager.FLAG_DISALLOW_OUT;
import static com.miui.enterprise.sdk.RestrictionsManager.BLUETOOTH_STATE;
import static com.miui.enterprise.sdk.RestrictionsManager.DISABLE;
import static com.miui.enterprise.sdk.RestrictionsManager.DISALLOW_CAMERA;
import static com.miui.enterprise.sdk.RestrictionsManager.DISALLOW_FACTORYRESET;
import static com.miui.enterprise.sdk.RestrictionsManager.DISALLOW_MTP;
import static com.miui.enterprise.sdk.RestrictionsManager.DISALLOW_RECORDING;
import static com.miui.enterprise.sdk.RestrictionsManager.DISALLOW_SCREENCAPTURE;
import static com.miui.enterprise.sdk.RestrictionsManager.DISALLOW_SDCARD;
import static com.miui.enterprise.sdk.RestrictionsManager.DISALLOW_SYSTEM_UPDATE;
import static com.miui.enterprise.sdk.RestrictionsManager.DISALLOW_TETHER;
import static com.miui.enterprise.sdk.RestrictionsManager.DISALLOW_TIMESET;
import static com.miui.enterprise.sdk.RestrictionsManager.DISALLOW_USBDEBUG;
import static com.miui.enterprise.sdk.RestrictionsManager.DISALLOW_USB_DEVICE;
import static com.miui.enterprise.sdk.RestrictionsManager.ENABLE;
import static com.miui.enterprise.sdk.RestrictionsManager.FORCE_OPEN;
import static com.miui.enterprise.sdk.RestrictionsManager.GPS_STATE;
import static com.miui.enterprise.sdk.RestrictionsManager.NFC_STATE;
import static com.miui.enterprise.sdk.RestrictionsManager.WIFI_STATE;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Build;
import android.view.KeyEvent;

import androidx.annotation.RequiresApi;

import com.miui.enterprise.sdk.ApplicationManager;
import com.miui.enterprise.sdk.DeviceManager;
import com.miui.enterprise.sdk.PhoneManager;
import com.miui.enterprise.sdk.RestrictionsManager;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class XiaomiMdmEngine extends BaseMDMEngine {

    private static final String TAG = "XiaomiMdmEngine";
    private RestrictionsManager restrictionsManager = RestrictionsManager.getInstance();
    private DeviceManager deviceManager = DeviceManager.getInstance();
    private PhoneManager phoneManager = PhoneManager.getInstance();
    private ApplicationManager applicationManager = ApplicationManager.getInstance();
    private PackageManager packageManager;

    public XiaomiMdmEngine(Context context) {
        super(context);
        String selfPkgName = context.getPackageName();
        applicationManager.grantSystemPermissions(Arrays.asList(selfPkgName),
                Arrays.asList("android.permission.INTERACT_ACROSS_USERS_FULL", "android.permission.INTERACT_ACROSS_USERS"));

        packageManager = context.getPackageManager();
        setApplicationsFlag(List.of(selfPkgName), FLAG_GRANT_ALL_RUNTIME_PERMISSION);
        if (!devicePolicyManager.isAdminActive(adminComponent)) {
            applicationManager.setDeviceAdmin(adminComponent);
        }
    }

    @Override
    public boolean isActiveDeviceAdmin() {
        return true;
    }

    @Override
    public boolean setActiveDeviceAdmin(Activity activity) {
        return true;
    }

    @Override
    public void controlBluetooth(boolean disabled) {
        restrictionsManager.setControlStatus(BLUETOOTH_STATE, disabled ? DISABLE : ENABLE);
    }

    @Override
    public boolean isBluetoothControlled() {
        return restrictionsManager.getControlStatus(BLUETOOTH_STATE) == DISABLE;
    }

    @Override
    public boolean setBluetoothWhiteList(List<String> whitList) {
        deviceManager.setBluetoothWhiteList(whitList);
        return true;
    }

    @Override
    public List<String> getBluetoothWhiteList() {
        return deviceManager.getBluetoothWhiteList();
    }


    @Override
    public void controlCamera(boolean disabled) {
        restrictionsManager.setRestriction(DISALLOW_CAMERA, disabled);
    }

    @Override
    public boolean isCameraControlled() {
        return restrictionsManager.hasRestriction(DISALLOW_CAMERA);
    }

    @Override
    public void controlWifi(boolean disabled) {
        restrictionsManager.setControlStatus(WIFI_STATE, disabled ? DISABLE : ENABLE);
    }

    @Override
    public boolean isWifiControlled() {
        return restrictionsManager.getControlStatus(WIFI_STATE) == DISABLE;
    }

    @Override
    public boolean setWifiWhiteList(List<String> whiteList) {
        deviceManager.setWifiApSsidWhiteList(whiteList);
        return true;
    }

    @Override
    public List<String> getWifiWhitList() {
        return deviceManager.getWifiApSsidWhiteList();
    }

    @Override
    public void controlMicroPhone(boolean disabled) {
        restrictionsManager.setRestriction(DISALLOW_RECORDING, disabled);
    }

    @Override
    public boolean isMicroPhoneControlled() {
        return restrictionsManager.hasRestriction(DISALLOW_RECORDING);
    }

    @Override
    public void controlExternalStorage(boolean disabled) {
        restrictionsManager.setRestriction(DISALLOW_SDCARD, disabled);
        restrictionsManager.setRestriction(DISALLOW_USB_DEVICE, disabled);
    }

    @Override
    public boolean isExternalStorageControlled() {
        return restrictionsManager.hasRestriction(DISALLOW_SDCARD);
    }

    @Override
    public void controlScreenShot(boolean disabled) {
        restrictionsManager.setRestriction(DISALLOW_SCREENCAPTURE, disabled);
    }

    @Override
    public boolean isScreenShotControlled() {
        return restrictionsManager.hasRestriction(DISALLOW_SCREENCAPTURE);
    }

    @Override
    public void controlNFC(boolean disabled) {
        restrictionsManager.setControlStatus(NFC_STATE, disabled ? DISABLE : ENABLE);
    }

    @Override
    public boolean isNFCControlled() {
        return restrictionsManager.getControlStatus(NFC_STATE) == DISABLE;
    }

    @Override
    public void controlMobileHotSpot(boolean disabled) {
        restrictionsManager.setRestriction(DISALLOW_TETHER, disabled);
    }

    @Override
    public boolean isMobileHotSpotControlled() {
        return restrictionsManager.hasRestriction(DISALLOW_TETHER);
    }

    @Override
    public void controlCallout(boolean disabled) {
        phoneManager.controlPhoneCall(disabled ? FLAG_DISALLOW_OUT : 0);
    }

    @Override
    public boolean isCalloutControlled() {
        return phoneManager.getPhoneCallStatus() != 0;
    }

    @Override
    public void controlSms(boolean disabled) {
        phoneManager.controlSMS(disabled ? (FLAG_DISALLOW_IN | FLAG_DISALLOW_OUT) : 0);
    }

    @Override
    public boolean isSmsControlled() {
        return phoneManager.getSMSStatus() != 0;
    }

    @Override
    public void controlMobileData(boolean disabled) {
        phoneManager.controlCellular(disabled ? DISABLE : ENABLE);
    }

    @Override
    public boolean isMobileDataControlled() {
        return phoneManager.getCellularStatus() != ENABLE;
    }

    @Override
    public void controlVolumeDown(boolean disabled) {
        if (disabled) {
            applicationManager.shortcutKeyActionForPackages(Arrays.asList(context.getPackageName()), KeyEvent.KEYCODE_VOLUME_DOWN, true);
        } else {
            applicationManager.removeShortcutKeyActionSettings(KeyEvent.KEYCODE_VOLUME_DOWN);
        }
    }

    @Override
    public boolean isVolumeDownControlled() {
        List list = applicationManager.getShortcutKeyActionPackages(KeyEvent.KEYCODE_VOLUME_DOWN);
        return (list != null && list.size() > 0);
    }

    @Override
    public void controlAutoTime(boolean disabled) {
        restrictionsManager.setRestriction(DISALLOW_TIMESET, disabled);
    }

    @Override
    public boolean isAutoTimeControlled() {
        return restrictionsManager.hasRestriction(DISALLOW_TIMESET);
    }

    @Override
    public void controlUsbData(boolean disabled) {
        restrictionsManager.setRestriction(DISALLOW_MTP, disabled);
        restrictionsManager.setRestriction(DISALLOW_USBDEBUG, disabled);
        this.controlExternalStorage(disabled);
    }

    @Override
    public boolean isUsbDataControlled() {
        return restrictionsManager.hasRestriction(DISALLOW_MTP);
    }

    @Override
    public void controlUsbDebug(boolean disabled) {
        restrictionsManager.setRestriction(DISALLOW_USBDEBUG, disabled);
    }

    @Override
    public boolean isUsbDebugControlled() {
        return restrictionsManager.hasRestriction(DISALLOW_USBDEBUG);
    }

    @Override
    public void controlRestoreFactory(boolean disabled) {
        restrictionsManager.setRestriction(DISALLOW_FACTORYRESET, disabled);
    }

    @Override
    public boolean isRestoreFactoryControlled() {
        return restrictionsManager.hasRestriction(DISALLOW_FACTORYRESET);
    }

    @Override
    public void controlSystemUpgrade(boolean disabled) {
        restrictionsManager.setRestriction(DISALLOW_SYSTEM_UPDATE, disabled);
    }

    @Override
    public boolean isSystemUpgradeControlled() {
        return restrictionsManager.hasRestriction(DISALLOW_SYSTEM_UPDATE);
    }

    @Override
    public void controlGPS(boolean disabled) {
        restrictionsManager.setControlStatus(GPS_STATE, disabled ? DISABLE : ENABLE);
    }

    @Override
    public boolean isGPSControlled() {
        return restrictionsManager.getControlStatus(GPS_STATE) == DISABLE;
    }

    @Override
    public void controlUnknownSource(boolean disabled) {
        applicationManager.enableTrustedAppStore(disabled);
    }

    @Override
    public boolean isUnknownSourceControlled() {
        return applicationManager.isTrustedAppStoreEnabled();
    }

    @Override
    public void controlForceGPS(boolean enabled) {
        restrictionsManager.setControlStatus(GPS_STATE, enabled ? FORCE_OPEN : ENABLE);
    }

    @Override
    public boolean isForceGPSControlled() {
        return restrictionsManager.getControlStatus(GPS_STATE) == FORCE_OPEN;
    }

    @Override
    public boolean setUnknownSourceWhiteList(List<String> packages) {
        applicationManager.addTrustedAppStore(packages);
        return true;
    }

    @Override
    public List<String> getUnknownSourceWhiteList() {
        return applicationManager.getTrustedAppStore();
    }

    @Override
    public boolean setDisallowRunningApps(List<String> packageNames, boolean isBlock) {
        if (isBlock) {
            applicationManager.setDisallowedRunningAppList(packageNames);
        } else {
            throw new NotSupportException("setDisallowRunningApps white list");
        }
        return true;
    }

    @Override
    public List<String> getDisallowRunningApps() {
        return applicationManager.getDisallowedRunningAppList();
    }

    @Override
    public boolean setUninstallblockApps(List<String> packageNames) {
        clearApplicationsWithFlag(FLAG_PREVENT_UNINSTALLATION);
        setApplicationsFlag(packageNames, FLAG_PREVENT_UNINSTALLATION);
        return true;
    }

    @Override
    public List<String> getUninstallblockApps() {
        return getApplicationsWithFlag(FLAG_PREVENT_UNINSTALLATION);
    }

    @Override
    public boolean setInstallblockApps(List<String> packageNames) {
        applicationManager.setApplicationBlackList(packageNames);
        return true;
    }

    @Override
    public List<String> getInstallblockApps() {
        return applicationManager.getApplicationBlackList();
    }

    @Override
    public void installPackage(String apkPath) {
        applicationManager.installPackage(apkPath, 0x00400000, null);
    }

    @Override
    public void uninstallPackage(String packageName) {
        applicationManager.deletePackage(packageName, 0, null);
    }

    @Override
    public void formatSDCard() {
        deviceManager.formatSdCard();
    }

    @Override
    public void factoryReset() {
        deviceManager.recoveryFactory(false);
    }

    @Override
    public boolean setInstallSourceApps(List<String> packageNames) {
        return false;
    }

    @Override
    public List<String> getInstallSourceApps() {
        return null;
    }

    @Override
    public boolean setNetworkBlackListAddress(List<String> address) {
        if (address == null || address.size() == 0) {
            deviceManager.setIpDomainBlackWhiteListPersistent(false);
            deviceManager.disableIpDomainBlackWhiteList();
        } else {
            if (!deviceManager.isIpDomainBlackWhiteListPersistent()) {
                deviceManager.setIpDomainBlackWhiteListPersistent(true);
            }
            deviceManager.setIpWhiteList(new ArrayList<>());
            deviceManager.setIpBlackList(address);
            deviceManager.setUrlWhiteList(new ArrayList<>());
            deviceManager.setUrlBlackList(address);
        }
        return true;
    }

    @Override
    public List<String> getNetworkBlackListAddress() {
        return deviceManager.getIpBlackList();
    }

    @Override
    public boolean setNetworkWhiteListAddress(List<String> address) {
        if (address == null || address.size() == 0) {
            deviceManager.setIpDomainBlackWhiteListPersistent(false);
            deviceManager.disableIpDomainBlackWhiteList();
        } else {
            if (!deviceManager.isIpDomainBlackWhiteListPersistent()) {
                deviceManager.setIpDomainBlackWhiteListPersistent(true);
            }
            deviceManager.setIpBlackList(new ArrayList<>());
            deviceManager.setIpWhiteList(address);
            deviceManager.setUrlBlackList(new ArrayList<>());
            deviceManager.setUrlWhiteList(address);
        }
        return true;
    }

    @Override
    public List<String> getNetworkWhiteListAddress() {
        return deviceManager.getIpWhiteList();
    }

    @Override
    public boolean setKeepLiveApps(List<String> packageNames) {
        clearApplicationsWithFlag(FLAG_KEEP_ALIVE | FLAG_ALLOW_AUTOSTART);
        setApplicationsFlag(packageNames, FLAG_KEEP_ALIVE | FLAG_ALLOW_AUTOSTART);
        return true;
    }

    @Override
    public List<String> getKeepLiveApps() {
        return getApplicationsWithFlag(FLAG_KEEP_ALIVE | FLAG_ALLOW_AUTOSTART);
    }

    @Override
    public boolean setSuperApps(List<String> packageNames) {
        return false;
    }

    @Override
    public List<String> getSuperApps() {
        return null;
    }

    @Override
    public boolean controlDeviceOwner(boolean enable) {
        if (enable) {
            if (!devicePolicyManager.isAdminActive(adminComponent)) {
                applicationManager.setDeviceAdmin(adminComponent);
            }
            if (!devicePolicyManager.isDeviceOwnerApp(context.getPackageName())) {
                applicationManager.setDeviceOwner(adminComponent);
                checkAndSetResetPasswordToken(context.getApplicationContext());
            }
        } else {
            try {
                devicePolicyManager.clearDeviceOwnerApp(context.getPackageName());
            } catch (Exception e) {
            }
        }
        return true;
    }

    @Override
    public boolean isDeviceOwnerControlled() {
        return devicePolicyManager.isDeviceOwnerApp(context.getPackageName());
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    public boolean setDevicePassword(String password) {
        boolean succeed = false;
        try {
            boolean isResetPasswordTokenActive = devicePolicyManager.isResetPasswordTokenActive(adminComponent);
            succeed = devicePolicyManager.resetPasswordWithToken(adminComponent, password, token, 0);
            devicePolicyManager.lockNow();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return succeed;
    }

    @Override
    public void shutdown() {
        deviceManager.deviceShutDown();
    }

    @Override
    public void reboot() {
        deviceManager.deviceReboot();
    }

    @Override
    public void powerOnAt(long time) {
    }

    @Override
    public String getName() {
        return "Redmi";
    }

    private void setApplicationsFlag(List<String> packageNames, int flag) {
        if (packageNames != null && packageNames.size() > 0) {
            for (String pkg : packageNames) {
                int curFlag = applicationManager.getApplicationSettings(pkg);
                curFlag = curFlag | flag;
                applicationManager.setApplicationSettings(pkg, curFlag);
            }
        }
    }

    private List<String> getApplicationsWithFlag(int flag) {
        List<String> packageNames = new ArrayList<>();
        final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
        mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
        final List<ResolveInfo> rinfo = packageManager.queryIntentActivities(mainIntent, PackageManager.MATCH_ALL);
        for (ResolveInfo resolveInfo : rinfo) {
            int curFlag = applicationManager.getApplicationSettings(resolveInfo.activityInfo.packageName);
            if ((curFlag & flag) == flag) {
                packageNames.add(resolveInfo.activityInfo.packageName);
            }
        }
        return packageNames;
    }

    private void clearApplicationsWithFlag(int flag) {
        int vFlag = ~flag;
        final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
        mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
        final List<ResolveInfo> rinfo = packageManager.queryIntentActivities(mainIntent, PackageManager.MATCH_ALL);
        for (ResolveInfo resolveInfo : rinfo) {
            int curFlag = applicationManager.getApplicationSettings(resolveInfo.activityInfo.packageName);
            if ((curFlag & flag) == flag) {
                applicationManager.setApplicationSettings(resolveInfo.activityInfo.packageName, curFlag & vFlag);
            }
        }
    }
}
